# used libraries
if (!require("ggplot2")) install.packages("ggplot2")
if (!require("plotly")) install.packages("plotly")
# R package DT provides an R interface to the JavaScript library DataTables.
if (!require("DT")) install.packages("DT")
# geom_mark_hull
if (!require("concaveman")) install.packages("concaveman")
if (!require("ggforce")) install.packages("ggforce")


# more libraries
if (!require("listviewer")) install.packages("listviewer")
if (!require("lubridate")) install.packages("lubridate")
if (!require("forcats")) install.packages("forcats")
if (!require("maps")) install.packages("maps")
if (!require("mvtnorm")) install.packages("mvtnorm")
if (!require("gapminder")) install.packages("gapminder")
if (!require("hexbin")) install.packages("hexbin")
if (!require("Hmisc")) install.packages("Hmisc")

plotly - Documentation

This document is essentially a brief notes of the book above.

Little Bit of Low-Level Details

Figure as List: list -> json -> plotly.js

library(plotly)
fig1 <- list(
  data = list(
    list(
      x = c(1, 2, 3),
      y = c(1, 3, 2),
      type = 'bar'
    )
  ),
  layout = list(
    title = 'A Figure Specified By R List',
    plot_bgcolor='#e5ecf6', 
         xaxis = list( 
           zerolinecolor = '#ffff', 
           zerolinewidth = 2, 
           gridcolor = 'ffff'), 
         yaxis = list( 
           zerolinecolor = '#ffff', 
           zerolinewidth = 2, 
           gridcolor = 'ffff')
  )
)
# To display the figure defined by this list, use the plotly_build function
plotly_build(fig1)
library(plotly) 

fig2 <- plot_ly(x = c(1, 2, 3), y = c(1, 3, 2), type = 'bar')%>% 
  layout(title = 'A Plotly Figure',
         plot_bgcolor='#e5ecf6', 
         xaxis = list( 
           zerolinecolor = '#ffff', 
           zerolinewidth = 2, 
           gridcolor = 'ffff'), 
         yaxis = list( 
           zerolinecolor = '#ffff', 
           zerolinewidth = 2, 
           gridcolor = 'ffff')) 
fig2
str(fig2, max.level = 2)
## List of 8
##  $ x            :List of 7
##   ..$ visdat     :List of 1
##   ..$ cur_data   : chr "18e8757d1eb5"
##   ..$ attrs      :List of 1
##   ..$ layout     :List of 3
##   ..$ source     : chr "A"
##   ..$ config     :List of 2
##   ..$ layoutAttrs:List of 1
##   ..- attr(*, "TOJSON_FUNC")=function (x, ...)  
##  $ width        : NULL
##  $ height       : NULL
##  $ sizingPolicy :List of 6
##   ..$ defaultWidth : chr "100%"
##   ..$ defaultHeight: num 400
##   ..$ padding      : num 0
##   ..$ viewer       :List of 6
##   ..$ browser      :List of 5
##   ..$ knitr        :List of 3
##  $ dependencies :List of 5
##   ..$ :List of 10
##   .. ..- attr(*, "class")= chr "html_dependency"
##   ..$ :List of 10
##   .. ..- attr(*, "class")= chr "html_dependency"
##   ..$ :List of 10
##   .. ..- attr(*, "class")= chr "html_dependency"
##   ..$ :List of 10
##   .. ..- attr(*, "class")= chr "html_dependency"
##   ..$ :List of 10
##   .. ..- attr(*, "class")= chr "html_dependency"
##  $ elementId    : NULL
##  $ preRenderHook:function (p, registerFrames = TRUE)  
##  $ jsHooks      : list()
##  - attr(*, "class")= chr [1:2] "plotly" "htmlwidget"
##  - attr(*, "package")= chr "plotly"
plotly_json(fig2)
## {
##   "visdat": {
##     "18e8757d1eb5": ["function () ", "plotlyVisDat"]
##   },
##   "cur_data": "18e8757d1eb5",
##   "attrs": {
##     "18e8757d1eb5": {
##       "x": [1, 2, 3],
##       "y": [1, 3, 2],
##       "alpha_stroke": 1,
##       "sizes": [10, 100],
##       "spans": [1, 20],
##       "type": "bar"
##     }
##   },
##   "layout": {
##     "margin": {
##       "b": 40,
##       "l": 60,
##       "t": 25,
##       "r": 10
##     },
##     "title": "A Plotly Figure",
##     "plot_bgcolor": "#e5ecf6",
##     "xaxis": {
##       "domain": [0, 1],
##       "automargin": true,
##       "zerolinecolor": "#ffff",
##       "zerolinewidth": 2,
##       "gridcolor": "ffff",
##       "title": []
##     },
##     "yaxis": {
##       "domain": [0, 1],
##       "automargin": true,
##       "zerolinecolor": "#ffff",
##       "zerolinewidth": 2,
##       "gridcolor": "ffff",
##       "title": []
##     },
##     "hovermode": "closest",
##     "showlegend": false
##   },
##   "source": "A",
##   "config": {
##     "modeBarButtonsToAdd": ["hoverclosest", "hovercompare"],
##     "showSendToCloud": false
##   },
##   "data": [
##     {
##       "x": [1, 2, 3],
##       "y": [1, 3, 2],
##       "type": "bar",
##       "marker": {
##         "color": "rgba(31,119,180,1)",
##         "line": {
##           "color": "rgba(31,119,180,1)"
##         }
##       },
##       "error_y": {
##         "color": "rgba(31,119,180,1)"
##       },
##       "error_x": {
##         "color": "rgba(31,119,180,1)"
##       },
##       "xaxis": "x",
##       "yaxis": "y",
##       "frame": null
##     }
##   ],
##   "highlight": {
##     "on": "plotly_click",
##     "persistent": false,
##     "dynamic": false,
##     "selectize": false,
##     "opacityDim": 0.2,
##     "selected": {
##       "opacity": 1
##     },
##     "debounce": 0
##   },
##   "shinyEvents": ["plotly_hover", "plotly_click", "plotly_selected", "plotly_relayout", "plotly_brushed", "plotly_brushing", "plotly_clickannotation", "plotly_doubleclick", "plotly_deselect", "plotly_afterplot", "plotly_sunburstclick"],
##   "base_url": "https://plot.ly"
## }

plotly.R to plotly.js

  • In principle you can update plotly list object to achive a particular effect
    • Typically we don’t whan to use it
  • plotly.R has many good routines to make our life easier

Overview

The Figure Data Structure (plotly object attributes):

Creating plotly object

plot_ly(): * ‘direct’ interface to plotly.js * additional abstractions to help reduce typing * Similar to ggplot2 plotly also implement Grammar of Graphics

Into to plot_ly

# load the plotly R package
library(plotly)

# load the diamonds dataset from the ggplot2 package
data(diamonds, package = "ggplot2")
#knitr::kable(diamonds)
diamonds
# create three visualizations of the diamonds dataset
plot_ly(diamonds, x = ~cut)
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
plot_ly(diamonds, x = ~cut, y = ~clarity)
## No trace type specified:
##   Based on info supplied, a 'histogram2d' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram2d
# using Accent palettes from RColorBrewer try Set1, Paired and others
plot_ly(diamonds, x = ~cut, color = ~clarity, colors = "Accent", type="histogram")
# doesn't produce black bars, 'black' is value here
plot_ly(diamonds, x = ~cut, color = "black")
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
# produces red bars with black outline
plot_ly(
  diamonds, 
  x = ~cut, 
  color = I("red"), 
  stroke = I("black"), 
  span = I(2)
)
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram

Use I(<value>) to specify color, mark and similar

Chaining with %>%

Most function from plotly takes a plotly object as first argument and thus can participate in %>% chaining.

layout(
  plot_ly(diamonds, x = ~cut),
  title = "My beatiful histogram"
)
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram

%>% often produce more human readable code

diamonds %>%
  plot_ly(x = ~cut) %>%
  layout(title = "My beatiful histogram")
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
diamonds %>%
  plot_ly() %>% 
  add_histogram(x = ~cut)
diamonds %>%
  dplyr::count(cut) %>%
  plot_ly() %>% 
  add_bars(x = ~cut, y = ~n)

What is the difference between two above plots?

Calculations done in different places (it can be important for speed and interactivity).

add_() functions: add_histogram2d(), add_contour(), add_boxplot()

plot_ly(): * Arguments specified in plot_ly() are global, meaning that any downstream add_() functions inherit these arguments (unless inherit = FALSE). manipulation verbs from the dplyr package may be used to transform the data underlying a plotly object. * use the plotly_data() to get data

library(dplyr)

diamonds %>%
  plot_ly(x = ~cut) %>% 
  add_histogram() %>%
  group_by(cut) %>%
  summarise(n = n()) %>%
  add_text(
    text = ~scales::comma(n), y = ~n, 
    textposition = "top middle", 
    cliponaxis = FALSE
  )

Into to ggplotly()

  • Converts ggplot graphics to plotly.
  • plotly does not have every possible plot in plot_ly(), so ggplotly extends interactivity to large set of ggplots.
  • Large number of plots converts properly.
p <- ggplot(diamonds, aes(x = log(carat), y = log(price))) + 
  geom_hex(bins = 100)
ggplotly(p)
p <- ggplot(diamonds, aes(x = log(price), color = clarity)) + 
    geom_freqpoly()
ggplotly(p)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
p <- ggplot(diamonds, aes(x = log(price), color = clarity)) + 
    geom_freqpoly(stat = "density") + 
    facet_wrap(~cut)
ggplotly(p)
m <- lm(log(price) ~ log(carat), data = diamonds)
diamonds <- modelr::add_residuals(diamonds, m)
p <- ggplot(diamonds, aes(x = clarity, y = resid, color = clarity)) +
    ggforce::geom_sina(alpha = 0.1) + 
    stat_summary(fun.data = "mean_cl_boot", color = "black") +
    facet_wrap(~cut)

# WebGL is a lot more efficient at rendering lots of points
toWebGL(ggplotly(p))

Scattered foundations

Some scatter type add_* routines: * add_markers() * add_lines() * add_paths() * add_segments() * add_ribbons() * add_area() * add_polygons()

library(plotly)
data(economics, package = "ggplot2")
economics
# show difference between paths and lines
p <- economics[sample(nrow(economics)),] %>%
  plot_ly(x = ~date, y = ~psavert)

add_paths(p)
add_lines(p)
add_lines(p) %>% rangeslider()
library(lubridate)
econ <- economics %>%
  mutate(yr = year(date), mnth = month(date))

# One trace (more performant, but less interactive) NOTE: group_by use
econ %>%
  group_by(yr) %>%
  plot_ly(x = ~mnth, y = ~uempmed) %>%
  add_lines()
# Multiple traces (less performant, but more interactive)
plot_ly(econ, x = ~mnth, y = ~uempmed) %>%
  add_lines(color = ~ordered(yr))
# The split argument guarantees one trace per group level (regardless 
# of the variable type). This is useful if you want a consistent
# visual property over multiple traces 
plot_ly(econ, x = ~mnth, y = ~uempmed) %>%
   add_lines(split = ~yr, color = I("black"))
#three above methods vary in interactivity and scaling/performance
# more raw plotly.js style, only add_trace
set.seed(99)
plot_ly() %>%
 add_trace(
   type = "scatter",
   mode = "markers+lines+text",
   x = 4:6, 
   y = 4:6,
   text = replicate(3, "Here is the text 🙌"),
   textposition = "right",
   hoverinfo = "text",
   textfont = list(family = "Roboto Condensed", size = 16)
 ) %>%
 layout(xaxis = list(range = c(3, 8)))
schema()
# add_markers adds markers/points
# alpha color can help with overcrowding
# too many points can be compute intensive, try toWebGL
# eventually you will need to use 2d histogram

subplot(
  plot_ly(mpg, x = ~cty, y = ~hwy, name = "default"),
  plot_ly(mpg, x = ~cty, y = ~hwy) %>% 
    add_markers(alpha = 0.2, name = "alpha")
)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

use suplot() for placing multiple plots on same figure

# use help and make it share X and Y axes

subplot(
  plot_ly(mpg, x = ~cty, y = ~hwy, name = "default"),
  plot_ly(mpg, x = ~cty, y = ~hwy) %>% 
    add_markers(alpha = 0.2, name = "alpha"),
  shareX=TRUE, shareY=T
)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

Discrete vs continuous color scale.

# discrete variable to color produces one trace per category,
# numeric variable to color produces one trace
# colorbar() - ustomize the appearance of scale bar
p <- plot_ly(mpg, x = ~cty, y = ~hwy, alpha = 0.5)
subplot(
  add_markers(p, color = ~cyl, showlegend = FALSE) %>% 
    colorbar(title = "Viridis"),
  add_markers(p, color = ~factor(cyl))
)

Specifying color palette.

Palettes types: * Sequential * gradual change from one color to another * typically light color to dark color * Good for continuous data, differentiate min and max * Diverging * Often gradual change between three colors * Good for continuous data, differentiate min, medium and max) * Qualitative * discrete color change, distinct colors between different values * Good for categories

library(RColorBrewer)
par(mar=c(3,4,2,2))
display.brewer.all()

subplot(
  add_markers(p, color = ~cyl, colors = c("red", "#000000", "blue")) %>%
    colorbar(title = "plotly"),
  add_markers(p, color = ~cyl, colors = "Spectral") %>% # RColorBrewer::brewer.pal.info for more
    colorbar(title = "RColorBrewer::Spectral"),
  add_markers(p, color = ~cyl, colors = viridisLite::inferno(10)) %>% 
    colorbar(title = "viridisLite::Inferno"),
  add_markers(p, color = ~cyl, colors = colorRamp(c("red", "white", "blue"))) %>% 
    colorbar(title = "colorRamp"),
  nrows = 2
) %>% hide_legend()
subplot(
  # plotly
  add_markers(p, color = ~factor(cyl), colors = c("red", "#000000", "blue","green"), 
              legendgroup = '1'),
  # plotly by values
  add_markers(p, color = ~factor(cyl), colors = c('4'="red", '5'="black", '6'="blue", '8'="green"), 
              legendgroup = '2'),
  # RColorBrewer::Set1
  add_markers(p, color = ~factor(cyl), colors = "Set1", 
              legendgroup = '3'),
  # colorRamp or other continious maps
  add_markers(p, color = ~factor(cyl), colors = colorRamp(c("red", "white", "blue")), 
              legendgroup = '4'),
  nrows = 2
)
# one legend per whole plot at this time, legendgroup allows grouping and some padding
subplot(
  add_markers(p, color = ~cyl, colors = c("red", "#000000", "blue")) %>%
    colorbar(title = "plotly"),
  add_markers(p, color = ~cyl, colors = "Spectral") %>% # RColorBrewer::brewer.pal.info for more
    colorbar(title = "RColorBrewer::Spectral"),
  add_markers(p, color = ~cyl, colors = viridisLite::inferno(10)) %>% 
    colorbar(title = "viridisLite::Inferno"),
  add_markers(p, color = ~cyl, colors = colorRamp(c("red", "white", "blue"))) %>% 
    colorbar(title = "colorRamp"),
  nrows = 2
) %>% hide_legend()

Symbols

p <- plot_ly(mpg, x = ~cty, y = ~hwy, alpha = 0.3) 
subplot(
  add_markers(p, symbol = ~cyl, name = "A single trace"),
  add_markers(p, symbol = ~factor(cyl), color = I("black")),
  add_markers(
    p, color = I("black"),
    symbol = ~factor(cyl), 
    symbols = c("triangle-up", "diamond", "circle")
  ),
  add_markers(p, size = ~cyl, sizes = c(1, 500), name = "custom"),
  nrows = 2
)
# stroke, span, size also can be changed
# add_segments
mpg %>%
  group_by(model) %>%
  summarise(c = mean(cty), h = mean(hwy)) %>%
  mutate(model = forcats::fct_reorder(model, c)) %>% # forcats::fct_reorder for factor reorder
  plot_ly() %>%
  add_segments(
    x = ~c, y = ~model,
    xend = ~h, yend = ~model, 
    color = I("gray"), showlegend = FALSE
  ) %>%
  add_markers(
    x = ~c, y = ~model, 
    color = I("blue"), 
    name = "mpg city"
  ) %>%
  add_markers(
    x = ~h, y = ~model, 
    color = I("red"),
    name  = "mpg highway"
  ) %>%
  layout(xaxis = list(title = "Miles per gallon"))
# leveraging density function to plot kernel dencity estimation
kerns <- c("gaussian", "epanechnikov", "rectangular", 
          "triangular", "biweight", "cosine", "optcosine")
p <- plot_ly()
for (k in kerns) {
  d <- density(economics$pce, kernel = k, na.rm = TRUE)
  p <- add_lines(p, x = d$x, y = d$y, name = k)
}
p
# or
ggplotly(ggplot(economics, aes(x=pce))+geom_density())

see more https://plotly-r.com/scatter-traces.html